using IQIGame.Onigao.Game;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 逻辑层实体寻路Agent组件
    /// 导航底层组件，不直接实现业务
    /// </summary>
    public class LgLevelNavigator : LogicBaseEntityComponent
    {
        public override uint MaxStore => 50;
        private static Vector3Logic InfinitePos = Vector3Logic.one * int.MinValue;
        private float[] _smoothPath;
        private int _nextPosIndex;
        private int _smoothPathCount;
        private Vector3Logic _nextPos;
        private Vector3Logic _lastDesPos = InfinitePos;
        private LevelEntity _entity;
        /// <summary>
        /// 常规寻路
        /// </summary>
        private bool _normalNavigating;
        /// <summary>
        /// 带有自动避障的寻路
        /// </summary>
        private bool _agentNavigating;
        private bool _setRotationOnStop;
        private int _stopRotationY;
        private int _navSpeed = LgLevelConst.EntitySpeed;
        /// <summary>
        /// 物理寻路载具（如电梯）
        /// 载具是可移动的，固定物理寻路区域可为null
        /// </summary>
        private LevelEntity _physicalCarrier;

        public bool isActive { get; private set; }
        public bool pathFinding { protected get; set; }
        public Vector3Logic destination => GetDestination();
        public bool isPhysical => _physicalCarrier != null;
        public bool isNavigating => _normalNavigating || _agentNavigating;

        public override void Awake(BaseEntity entity)
        {
            this._entity = entity as LevelEntity;
            isActive = true;
        }

        public void SwitchPhysicNavMode(LevelEntity physicalCarrier)
        {
            this._physicalCarrier = physicalCarrier;
        }

        public bool IsInPhysicalArea(Vector3Logic targetPosition)
        {
            if (_physicalCarrier == null)
            {
                LogicLog.LogWarning("英雄物理移动失败，不是物理寻路模式。");
                return false;
            }
            bool isValid = LgLevelEntityUtil.XYCenterRectContains(targetPosition, _physicalCarrier.position, _physicalCarrier.triggerRect.ExtendsSize(1.1f), out int errorCode);
            if (!isValid)
            {
                if (errorCode == 1)
                {
                    LogicLog.LogWarning("英雄物理移动失败，和物理区域的高度差距太大。");
                }
                else
                {
                    LogicLog.LogWarning("英雄物理移动失败，不在物理矩形区域内。");
                }
            }
            return isValid;
        }

        public bool NavigateTo(Vector3Logic position, int speed, int stopRotationY)
        {
            bool isOK = NavigateTo(position, speed);
            if (isOK)
            {
                _setRotationOnStop = true;
                _stopRotationY = stopRotationY;
            }
            return isOK;
        }

        public bool NavigateTo(Vector3Logic position, int speed)
        {
            SetSpeed(speed);
            isActive = true;
            if (!_entity.isObstacleActive)
            {
                return SetDestination(position);
            }
            else if (_entity.IsMovableObstacle())
            {
                return AgentHeadTo(position);
            }
            else
            {
                LogicLog.LogError($"实体 mcid {_entity.entityConfig?.id} 不支持寻路。是否是静态阻挡 {_entity.entityConfig.obstacle.isStatic} ObstacleId {_entity.ObstacleId}");
            }
            return false;
        }

        public void SetSpeed(int speed)
        {
            if (speed != _navSpeed)
            {
                _navSpeed = speed;
                if (_entity.IsMovableObstacle())
                {
                    _entity.region.ChangeEntityAgentSpeed(_entity, speed, LgLevelConst.AgentMaxAcceleration);
                }
            }
        }

        private bool SetDestination(Vector3Logic targetPos)
        {
            if (_lastDesPos == targetPos)
            {
                return false;
            }

            Vector3Logic startPos = _entity.position;
            _lastDesPos = targetPos;

            _smoothPathCount = _entity.region.terrain.FindPath(startPos, targetPos, out _smoothPath);
            if (_smoothPathCount <= 0)
            {
                _normalNavigating = false;
                return false;
            }

            _normalNavigating = true;

            _nextPosIndex = 0;
            PathNextPosition();

            return true;
        }

        private float GetSpeedRatio()
        {
            return (float)_navSpeed / _entity.defaultMoveSpeed;
        }

        /// <summary>
        /// 停止寻路
        /// </summary>
        /// <param name="resetSpeed"></param>
        /// <param name="stopPos">停止位置，如果是阻挡避障模式，必须传该参数</param>
        public void StopNavigation(bool resetSpeed, Vector3Logic stopPos)
        {
            bool moveSuccess;
            if ((stopPos - _entity.position).sqrMagnitude > LgLevelConst.SamePositionSqrtRange)
            {
                moveSuccess = _entity.MoveInNavMesh(stopPos, GetSpeedRatio(), true);
            }
            else
            {
                moveSuccess = true;
            }
            if (!moveSuccess)
            {
                LogicLog.LogError($"停止导航失败，移动到指定点{stopPos}发生错误。");
                return;
            }
            if (_normalNavigating)
            {
                _normalNavigating = false;
            }
            else if (_agentNavigating)
            {
                AgentStopAt(stopPos, false);
                _agentNavigating = false;
            }
            _setRotationOnStop = false;
            _stopRotationY = 0;
            if (resetSpeed)
            {
                SetSpeed(_entity.moveSpeed);
            }
        }

        private void PathNextPosition()
        {
            _nextPosIndex++;
            if (_nextPosIndex >= _smoothPathCount)
            {
                _nextPosIndex = 0;
            }
            _nextPos.Set(-_smoothPath[_nextPosIndex * 3] * LgLevelConst.DistanceUnitRatio, _smoothPath[_nextPosIndex * 3 + 1] * LgLevelConst.DistanceUnitRatio, _smoothPath[_nextPosIndex * 3 + 2] * LgLevelConst.DistanceUnitRatio);
        }

        private Vector3Logic GetDestination()
        {
            if (!isNavigating)
            {
                return _entity.position;
            }
            if (_agentNavigating)
            {
                return _lastDesPos;
            }
            if (_normalNavigating)
            {
                if (_smoothPathCount <= 0)
                {
                    LogicLog.LogError("获取寻路目标点失败，处于常规模式，但路径点数量<=0。");
                    return Vector3Logic.zero;
                }
                int theLastIndex = _smoothPathCount - 1;
                return new Vector3Logic(-_smoothPath[theLastIndex * 3] * LgLevelConst.DistanceUnitRatio, _smoothPath[theLastIndex * 3 + 1] * LgLevelConst.DistanceUnitRatio, _smoothPath[theLastIndex * 3 + 2] * LgLevelConst.DistanceUnitRatio);
            }
            LogicLog.LogError("获取寻路目标点失败，状态非法，既不处于避障模式，也不处于常规模式。");
            return Vector3Logic.zero;
        }

        private bool AgentHeadTo(Vector3Logic targetPos)
        {
            if (_lastDesPos == targetPos)
            {
                return false;
            }
            _lastDesPos = targetPos;

            if (_entity is not LevelEntity)
            {
                LogicLog.LogError($"移动阻挡实体失败，不支持的实体类型：{_entity.GetType()}");
                return false;
            }

            bool result = _entity.region.terrain.AgentHeadTo(_entity.ObstacleId, targetPos);
            _agentNavigating = result;
            return result;
        }

        /// <summary>
        /// 让agent（动态避障单位）停止在指定位置
        /// </summary>
        /// <param name="targetPos"></param>
        /// <param name="instantlyStopAtOtherPos">当停止位置不是当前agent所在位置时，是否需要立即瞬移到指定位置</param>
        /// <returns></returns>
        private bool AgentStopAt(Vector3Logic targetPos, bool instantlyStopAtOtherPos)
        {
            if (!_agentNavigating)
            {
                return false;
            }
            _lastDesPos = targetPos;

            bool result = false;
            if (instantlyStopAtOtherPos)
            {
                result = _entity.region.terrain.TeleportAgentTo(_entity.ObstacleId, targetPos);
            }
            else
            {
                result = _entity.region.terrain.AgentHeadTo(_entity.ObstacleId, targetPos);
            }
            return result;
        }

        public void SetActive(bool isActive)
        {
            if (this.isActive == isActive)
            {
                return;
            }
            this.isActive = isActive;
            //停止寻路，agent寻路需特殊处理，因为其控制在recast nav内部，不是我们自己控制的
            if (!isActive && _agentNavigating)
            {
                AgentStopAt(_entity.position, false);
            }
            else if (isActive)
            {
                LevelEntity entity = (LevelEntity)_entity;
                if (!entity.entityConfig.obstacle.isStatic && entity.ObstacleId != 0)
                {
                    AgentHeadTo(_lastDesPos);
                }
            }
        }

        public override void LogicOnUpdate()
        {
            if (!isActive)
            {
                return;
            }
            if (_normalNavigating)
            {
                Vector3Logic dir = (_nextPos - _entity.position).normalized;
                Vector3Logic displacement = dir * _navSpeed * LgLevelConst.deltaTime;

                if (displacement.sqrMagnitude == 0 || displacement.sqrMagnitude >= (_nextPos - _entity.position).sqrMagnitude)
                {
                    _entity.UpdateMove(_nextPos, GetSpeedRatio());

                    if (_smoothPathCount == _nextPosIndex + 1)
                    {
                        _entity.UpdateMove(_lastDesPos, GetSpeedRatio());
                        _normalNavigating = false;
                        _lastDesPos = InfinitePos;
                        SetSpeed(_entity.moveSpeed);
                        if (_setRotationOnStop)
                        {
                            _entity.SetRotationY(_stopRotationY, true);
                            _setRotationOnStop = false;
                            _stopRotationY = 0;
                        }
                        return;
                    }
                    PathNextPosition();
                }
                else
                {
                    _entity.UpdateMove(_entity.position + displacement, GetSpeedRatio());
                }
            }
            else if (_agentNavigating)
            {
                if (_entity is LevelEntity)
                {
                    Vector3Logic curPos = _entity.region.terrain.GetAgentPos(_entity.ObstacleId);
                    Vector3Logic distance = _lastDesPos - curPos;
                    _entity.UpdateMove(curPos, GetSpeedRatio());
                    if (distance.sqrMagnitude <= LgLevelConst.SamePositionSqrtRange)
                    {
                        _entity.region.terrain.AgentHeadTo(_entity.ObstacleId, _lastDesPos);
                        _entity.UpdateMove(_lastDesPos, GetSpeedRatio());
                        _agentNavigating = false;
                        _lastDesPos = InfinitePos;
                        SetSpeed(_entity.moveSpeed);
                        if (_setRotationOnStop)
                        {
                            _entity.SetRotationY(_stopRotationY, true);
                            _setRotationOnStop = false;
                            _stopRotationY = 0;
                        }
                    }
                }
            }
        }

        public override void OnRelease()
        {
            _entity = null;
            isActive = false;
            _lastDesPos = InfinitePos;
            _navSpeed = LgLevelConst.EntitySpeed;
        }
    }
}
